/*
 * Copyright (c) 2020, HiHope Community.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * 1. Redistributions of source code must retain the above copyright notice, this
 *    list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright notice,
 *    this list of conditions and the following disclaimer in the documentation
 *    and/or other materials provided with the distribution.
 *
 * 3. Neither the name of the copyright holder nor the names of its
 *    contributors may be used to endorse or promote products derived from
 *    this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include <stdio.h>
#include <unistd.h>

#include "ohos_init.h"
#include "cmsis_os2.h"
#include <stdio.h>
#include "cmsis_os2.h"
#include "ohos_run.h"
#include "esp_system.h"
#include "nvs_flash.h"
#include "esp_log.h"
#include "driver/gpio.h"
#include "driver/i2c.h"

#include "ssd1306.h"
#include "ssd1306_tests.h"

#define GPIO_A GPIO_NUM_4
#define GPIO_B GPIO_NUM_0
#define OLED_I2C_BAUDRATE 400 * 1000

/**
 * 汉字字模在线： https://www.23bei.com/tool-223.html
 * 数据排列：从左到右从上到下
 * 取模方式：横向8位左高位
 **/
void TestDrawChinese1(void)
{
    const uint32_t W = 16, H = 16;
    uint8_t fonts[][32] = {
        /* [字库]：[HZK1616宋体] [数据排列]:从左到右从上到下 [取模方式]:横向8点左高位 [正负反色]:否 [去掉重复后]共6个字符
[总字符库]："　鸿蒙实验箱"*/

        /*-- ID:0,字符:"　",ASCII编码:A1A1,对应字:宽x高=16x16,画布:宽W=16 高H=16,共32字节*/
        {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}
        /*-- ID:1,字符:"鸿",ASCII编码:BAE8,对应字:宽x高=16x16,画布:宽W=16 高H=16,共32字节*/
        {0x40, 0x20, 0x30, 0x48, 0x10, 0xFC, 0x02, 0x88, 0x9F, 0xA8, 0x64, 0x88, 0x24, 0xA8, 0x04, 0x90,
         0x14, 0x84, 0x14, 0xFE, 0xE7, 0x04, 0x3C, 0x24, 0x29, 0xF4, 0x20, 0x04, 0x20, 0x14, 0x20, 0x08}
        /*-- ID:2,字符:"蒙",ASCII编码:C3C9,对应字:宽x高=16x16,画布:宽W=16 高H=16,共32字节*/
        {0x04, 0x48, 0x7F, 0xFC, 0x04, 0x40, 0x7F, 0xFE, 0x40, 0x02, 0x8F, 0xE4, 0x00, 0x00, 0x7F, 0xFC,
         0x06, 0x10, 0x3B, 0x30, 0x05, 0xC0, 0x1A, 0xA0, 0x64, 0x90, 0x18, 0x8E, 0x62, 0x84, 0x01, 0x00}
        /*-- ID:3,字符:"实",ASCII编码:CAB5,对应字:宽x高=16x16,画布:宽W=16 高H=16,共32字节*/
        {0x02, 0x00, 0x01, 0x00, 0x7F, 0xFE, 0x48, 0x02, 0x86, 0x84, 0x02, 0x80, 0x10, 0x80, 0x0C, 0x80,
         0x04, 0x84, 0xFF, 0xFE, 0x01, 0x00, 0x01, 0x40, 0x02, 0x20, 0x04, 0x10, 0x18, 0x0C, 0x60, 0x04}
        /*-- ID:4,字符:"验",ASCII编码:D1E9,对应字:宽x高=16x16,画布:宽W=16 高H=16,共32字节*/
        {0x08, 0x40, 0xFC, 0x40, 0x08, 0xA0, 0x48, 0xA0, 0x49, 0x10, 0x4A, 0x0E, 0x4D, 0xF4, 0x48, 0x00,
         0x7C, 0x48, 0x06, 0x48, 0x05, 0x48, 0x1D, 0x50, 0xE5, 0x10, 0x44, 0x24, 0x17, 0xFE, 0x08, 0x00}
        /*-- ID:5,字符:"箱",ASCII编码:CFE4,对应字:宽x高=16x16,画布:宽W=16 高H=16,共32字节*/
        {0x12, 0x44, 0x1F, 0x7E, 0x28, 0xA0, 0x45, 0x10, 0x08, 0x04, 0x08, 0xFE, 0xFE, 0x84, 0x08, 0x84,
         0x18, 0xFC, 0x1C, 0x84, 0x2A, 0x84, 0x28, 0xFC, 0x48, 0x84, 0x88, 0x84, 0x08, 0xFC, 0x08, 0x84}};

    ssd1306_Fill(Black);
    for (size_t i = 0; i < sizeof(fonts) / sizeof(fonts[0]); i++)
    {
        ssd1306_DrawRegion(i * W, 18, W, H, fonts[i], sizeof(fonts[0]), W);
    }
    ssd1306_UpdateScreen();
    sleep(1);
}

void TestDrawChinese2(void)
{
    const uint32_t W = 12, H = 12, S = 16;
    uint8_t fonts[][24] = {
        /* [字库]：[HZK1212宋体] [数据排列]:从左到右从上到下 [取模方式]:横向8点左高位 [正负反色]:否 [去掉重复后]共9个字符
        [总字符库]："　－ＯＬＥＤ屏案例"*/
        /*-- ID:0,字符:"　",ASCII编码:A1A1,对应字:宽x高=12x12,画布:宽W=16 高H=12,共24字节*/
        {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}
        /*-- ID:1,字符:"－",ASCII编码:A3AD,对应字:宽x高=12x12,画布:宽W=16 高H=12,共24字节*/
        {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F, 0x00, 0x00, 0x00, 0x00, 0x00,
         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}
        /*-- ID:2,字符:"Ｏ",ASCII编码:A3CF,对应字:宽x高=12x12,画布:宽W=16 高H=12,共24字节*/
        {0x00, 0x00, 0x1C, 0x00, 0x36, 0x00, 0x63, 0x00, 0x63, 0x00, 0x63, 0x00, 0x63, 0x00, 0x63, 0x00,
         0x36, 0x00, 0x1C, 0x00, 0x00, 0x00, 0x00, 0x00}
        /*-- ID:3,字符:"Ｌ",ASCII编码:A3CC,对应字:宽x高=12x12,画布:宽W=16 高H=12,共24字节*/
        {0x00, 0x00, 0x78, 0x00, 0x30, 0x00, 0x30, 0x00, 0x30, 0x00, 0x30, 0x00, 0x30, 0x00, 0x31, 0x00,
         0x33, 0x00, 0x7F, 0x00, 0x00, 0x00, 0x00, 0x00}
        /*-- ID:4,字符:"Ｅ",ASCII编码:A3C5,对应字:宽x高=12x12,画布:宽W=16 高H=12,共24字节*/
        {0x00, 0x00, 0x7F, 0x00, 0x33, 0x00, 0x31, 0x00, 0x34, 0x00, 0x3C, 0x00, 0x34, 0x00, 0x31, 0x00,
         0x33, 0x00, 0x7F, 0x00, 0x00, 0x00, 0x00, 0x00}
        /*-- ID:5,字符:"Ｄ",ASCII编码:A3C4,对应字:宽x高=12x12,画布:宽W=16 高H=12,共24字节*/
        {0x00, 0x00, 0x7C, 0x00, 0x36, 0x00, 0x33, 0x00, 0x33, 0x00, 0x33, 0x00, 0x33, 0x00, 0x33, 0x00,
         0x36, 0x00, 0x7C, 0x00, 0x00, 0x00, 0x00, 0x00}
        /*-- ID:6,字符:"屏",ASCII编码:C6C1,对应字:宽x高=12x12,画布:宽W=16 高H=12,共24字节*/
        {0x7F, 0xE0, 0x40, 0x20, 0x7F, 0xE0, 0x48, 0x80, 0x45, 0x00, 0x5F, 0xE0, 0x44, 0x80, 0x7F, 0xF0,
         0x44, 0x80, 0x44, 0x80, 0x48, 0x80, 0x90, 0x80}
        /*-- ID:7,字符:"案",ASCII编码:B0B8,对应字:宽x高=12x12,画布:宽W=16 高H=12,共24字节*/
        {0x04, 0x00, 0x7F, 0xF0, 0xC8, 0x20, 0x7F, 0xF0, 0x11, 0x00, 0x0E, 0x00, 0x71, 0xC0, 0x04, 0x00,
         0xFF, 0xF0, 0x15, 0x00, 0x24, 0xC0, 0xC4, 0x30}
        /*-- ID:8,字符:"例",ASCII编码:C0FD,对应字:宽x高=12x12,画布:宽W=16 高H=12,共24字节*/
        {0x10, 0x10, 0x1F, 0x90, 0x24, 0x50, 0x27, 0x50, 0x69, 0x50, 0xA9, 0x50, 0x35, 0x50, 0x22, 0x50,
         0x22, 0x10, 0x24, 0x10, 0x28, 0x50, 0x30, 0x20}};
    ssd1306_Fill(Black);
    for (size_t i = 0; i < sizeof(fonts) / sizeof(fonts[0]); i++)
    {
        ssd1306_DrawRegion(i * H, 18, W, H, fonts[i], sizeof(fonts[0]), S); // y= 18 居中显示
    }
    ssd1306_UpdateScreen();
    sleep(1);
}

void Ssd1306TestTask(void *arg)
{
    (void)arg;

    i2c_config_t i2c_initer = {
        .clk_flags = 0,            // 选择默认时钟源
        .master.clk_speed = 50000, // 指定速率为100Kbit,最大可以为400Kbit
        .mode = I2C_MODE_MASTER,   // 主机模式
        .scl_io_num = 17,          // 指定SCL的GPIO口
        .scl_pullup_en = true,     // SCL接上拉电阻
        .sda_io_num = 16,          // 指定SDA的GPIO口
        .sda_pullup_en = true,     // SDA接上拉电阻
    };
    if (i2c_param_config(I2C_NUM_0, &i2c_initer) == ESP_OK)
    {
        printf("i2c parm config success\r\n");
    }
    else
    {
        printf("config fail\r\n");
    }

    if (i2c_driver_install(I2C_NUM_0, I2C_MODE_MASTER, 0, 0, 0) == ESP_OK)
    {
        printf("i2c driver install success\r\n");
    }
    else
    {
        printf("driver fail\r\n");
    }

    // 配置GPIO为输入
    gpio_config_t gpio_a = {
        .intr_type = GPIO_INTR_DISABLE,
        .mode = GPIO_MODE_INPUT,
        .pin_bit_mask = 1ULL << GPIO_A,
        .pull_down_en = GPIO_PULLDOWN_DISABLE,
        .pull_up_en = GPIO_PULLUP_ENABLE};

    gpio_config(&gpio_a);

    gpio_config_t gpio_b = {
        .intr_type = GPIO_INTR_DISABLE,
        .mode = GPIO_MODE_INPUT,
        .pin_bit_mask = 1ULL << GPIO_B,
        .pull_down_en = GPIO_PULLDOWN_DISABLE,
        .pull_up_en = GPIO_PULLUP_ENABLE};

    gpio_config(&gpio_b);

    usleep(20 * 1000);
    ssd1306_Init();
    ssd1306_Fill(Black);
    ssd1306_SetCursor(0, 0);

    while (1)
    {
        if (gpio_get_level(GPIO_A) == 0)
        {
            TestDrawChinese1();
            ssd1306_UpdateScreen();
        }
        else if (gpio_get_level(GPIO_B) == 0)
        {
            TestDrawChinese2();
            ssd1306_UpdateScreen();
        }
    }
}

void Ssd1306TestDemo(void)
{
    osThreadAttr_t attr;

    attr.name = "Ssd1306Task";
    attr.attr_bits = 0U;
    attr.cb_mem = NULL;
    attr.cb_size = 0U;
    attr.stack_mem = NULL;
    attr.stack_size = 10240;
    attr.priority = osPriorityNormal;

    if (osThreadNew(Ssd1306TestTask, NULL, &attr) == NULL)
    {
        printf("[Ssd1306TestDemo] Falied to create Ssd1306TestTask!\n");
    }
}
OHOS_APP_RUN(Ssd1306TestDemo);
